import { _decorator, Component, Node, sys } from 'cc';
const { ccclass } = _decorator;

/**
 * 网络管理器
 */
@ccclass("J_NetworkManager")
export class NetworkManager extends Component {

    // ws 客户端
    private _ws: WebSocket | null = null;
    // ws 服务端 URL
    private _ws_url = 'ws://139.224.217.197:8085/ws';
    // ws 记录最后一次消息
    private _ws_message: string = '';
    // ws 重连接次数
    private _reconnect_count: number = 0;
    // ws 接收消息回调
    private _ws_onmessage_func = null;
    // http
    private _xhr: XMLHttpRequest | null = null;

    public constructor() {
        super();
    }

    // 管理器初始化
    static init(_jees: any, _node: Node) {
        _jees.N = _node.addComponent(NetworkManager);
    }

    start() {
        this.initWebSocket();
    }

    ///
    /// http 部分
    ///

    /**
     * GET 请求
     * @param _url 请求地址，加参数
     * @param _cb 回调
     */
    httpGet(
        _url: string,
        _cb: (status: number, res?: object | null) => any) {
        this.http(_url, 'GET', null, _cb);
    }

    /**
     * POST 请求
     * @param _url 请求地址
     * @param _body 请求体
     * @param _cb 回调
     */
    httpPost(
        _url: string,
        _body: object,
        _cb: (status: number, res?: object | null) => any
    ) {
        this.http(_url, 'POST', _body, _cb);
    }

    /**
     * PUT 请求
     * @param _url 请求地址
     * @param _body 请求体
     * @param _cb 回调
     */
    httpPut(
        _url: string,
        _body: object,
        _cb: (status: number, res?: object | null) => any
    ) {
        this.http(_url, 'PUT', _body, _cb);
    }

    /**
     * DELETE 请求
     * @param _url 请求地址
     * @param _body 请求体
     * @param _cb 回调
     */
    httpDelete(
        _url: string,
        _body: object,
        _cb: (status: number, res?: object | null) => any
    ) {
        this.http(_url, 'DELETE', _body, _cb);
    }

    /**
     * 请求 json 格式
     * @param _url 请求地址
     * @param _method 请求方式
     * @param _body 请求体
     * @param _cb 回调
     */
    http(_url: string, _method: string, _body: object, _cb: (status: number, res?: object | null) => any) {
        let xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            let readyState = xhr.readyState;
            let status = xhr.status;
            let label;
            if (readyState === 4 && status >= 200) {
                let response = xhr.responseText;
                label = JSON.parse(response);
                _cb(status, label);
            } else if (status === 404) {
                label = '404 page not found!';
            } else if (readyState === 3) {
                label = 'Request dealing!';
            } else if (readyState === 2) {
                label = 'Request received!';
            } else if (readyState === 1) {
                label = 'Server connection established! Request hasn\'t been received';
            } else if (readyState === 0) {
                label = 'Request hasn\'t been initiated!';
            }
        };
        xhr.open(_method, _url, true);
        if (sys.isNative) {
            xhr.setRequestHeader('Accept-Encoding', 'gzip,deflate');
        }
        xhr.setRequestHeader('Content-Type', 'application/json');
        // xhr.setRequestHeader('Authorization', 'Bearer ' + "");
        xhr.timeout = 10000;
        if (_body) {
            xhr.send(JSON.stringify(_body));
        } else {
            xhr.send();
        }
        this._xhr = xhr;
    }

    /**
     * 移除所有 xhr 监听
     * @param xhr xhr
     */
    rmXhrEventListener(xhr: any) {
        if (!xhr) return;
        ['loadstart', 'abort', 'error', 'load', 'loadend', 'timeout'].forEach((eventName) => {
            xhr['on' + eventName] = null;
        });
        xhr.onreadystatechange = null;
    }

    ///
    /// websocket 部分
    ///

    /**
     * 向 WebSocket Server 发送二进制消息
     * @param _msg 消息字符串内容
     */
    sendBinary(_msg: string) {
        if (!this._ws) return;
        if (this._ws.readyState === WebSocket.OPEN) {
            let buf = _msg;
            let arrData = new Uint16Array(buf.length);
            for (let i = 0; i < buf.length; i++) {
                arrData[i] = buf.charCodeAt(i);
            }
            this._ws.send(arrData.buffer);
        } else {
            this._ws_message = 'WebSocket: not ready';
            this.scheduleOnce(() => {
                this.sendBinary(_msg);
            }, 2);
        }
    }

    /**
     * 向 WebSocket Server 发送文本消息
     * @param _msg 消息内容
     * @param _more 多参
     */
    sendText(_msg: string, ..._more: string[]) {
        if (!this._ws) return;
        if (this._ws.readyState === WebSocket.OPEN) {
            this._ws.send(_msg);
            if (_more.length > 0) {
                for (let _m of _more) {
                    this._ws.send(_m);
                }
            }
        } else {
            this._ws_message = 'WebSocket: not ready';
            this.scheduleOnce(() => {
                this.sendText(_msg, ..._more);
            }, 2);
        }
    }

    /**
     * 接收 Server 消息
     * @param _cb 回调
     */
    receiveMessage(_cb: any) {
        this._ws_onmessage_func = _cb;
    }

    /**
     * 获取最后一次记录的消息
     */
    getLastMessage() {
        return this._ws_message;
    }

    /**
     * 初始化 WebSocket 客户端
     */
    initWebSocket() {
        const self = this;

        this._ws = new WebSocket(this._ws_url || 'ws://localhost', []);

        // 开启
        this._ws.onopen = function (evt) {
            self._ws_message = 'WebSocket: onopen';
        };

        // 接收消息
        this._ws.onmessage = function (evt) {
            const { type, data } = evt;
            self._ws_message = data;
            if (type === 'message') {
                let res = {};
                try {
                    res = {
                        type: 'json',
                        data: JSON.parse(data)
                    };
                } catch (e) {
                    res = {
                        type: 'text',
                        data
                    };
                }
                if (self._ws_onmessage_func) {
                    self._ws_onmessage_func(res);
                }
            }

        };

        // 错误
        this._ws.onerror = function (evt) {
            self._ws_message = 'WebSocket: onerror';
        };

        // 关闭
        this._ws.onclose = function (evt) {
            self._ws_message = 'WebSocket: onclose';
            self._ws = null;
        };
    }

    /**
     * 组件销毁
     */
    onDestroy() {
        this._ws_onmessage_func = null;
        this._ws_message = '';
        this._reconnect_count = 0;
        let wsc = this._ws;
        if (wsc) {
            wsc.onopen = null;
            wsc.onmessage = null;
            wsc.onerror = null;
            wsc.onclose = null;
            wsc.close();
        }
        this.rmXhrEventListener(this._xhr);
    }

}